﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using MockFramework.DataModels;

namespace MockFramework.ControlServices
{
    public static class ManageProxyClasses
    {
        public static bool IsOverriding(this MethodInfo methodInfo)
        {
            if (methodInfo == null) throw new ArgumentNullException("No MethodInfo...");
            return methodInfo.DeclaringType != methodInfo.GetBaseDefinition().DeclaringType;
        }

        public static Proxy DefineProxyClass(Type cpc)
        {
            Proxy proxyClass = new Proxy();
            proxyClass.proxyClassName = cpc.Name;
            proxyClass.methodsList = new List<ProxyMethod>();
            MethodInfo[] methodinfo = cpc.GetMethods();
            List<String> usings = new List<String>();

            foreach (var mi in methodinfo)
            {
                if (mi.IsVirtual)
                {
                    ProxyMethod pm = new ProxyMethod();
                    pm.isOverride = mi.IsOverriding();
                    pm.methodName = mi.Name;
                    pm.methodReturnType = mi.ReturnType.Name.ToString();

                    Console.WriteLine("Methodname: " + pm.methodName);
                    Console.WriteLine("methodReturnType.Name: " + pm.methodReturnType);
                    Console.WriteLine("Length: " + mi.ReturnType.GetGenericArguments().Length);
                    for(int i = 0; i < mi.ReturnType.GetGenericArguments().Length; ++i)
                    {
                        Console.WriteLine("GetGenericArguments: " + mi.ReturnType.GetGenericArguments()[i].Name);
                    }
                    Console.WriteLine("methodReturnType : " + pm.methodReturnType);
                    Console.WriteLine("_____________________________________________");
                    pm.paramList = mi.GetParameters();

                    // Get the Namespace of members, params and types defined in the class
                    foreach (
                    var mb in
                        mi.DeclaringType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static |
                                                   BindingFlags.NonPublic))
                    {
                        if (mb.MemberType == MemberTypes.Method && ((MethodBase)mb).GetMethodBody() != null)
                        {
                            foreach (var p in ((MethodInfo)mb).GetMethodBody().LocalVariables)
                            {
                                if (!usings.Contains(p.LocalType.Namespace))
                                {
                                    usings.Add(p.LocalType.Namespace);
                                }
                            }
                        }
                        else if (mb.MemberType == MemberTypes.Field)
                        {
                            string ns = ((System.Reflection.FieldInfo)mb).FieldType.Namespace;
                            if (!usings.Contains(ns))
                            {
                                usings.Add(ns);
                            }
                        }
                    }
                    proxyClass.methodsList.Add(pm);
                }
            }
            proxyClass.usingsList = usings;
            return proxyClass;
        }
    

        public static String CreateProxyClass(Proxy proxyClass)
        {
            //string cSharpSourceCode = @"using System; ";
            string cSharpSourceCode = @"";
            foreach (String ns in proxyClass.usingsList)
            {
                cSharpSourceCode += "using " + ns + ";\n";
            }
            //Object_Proxy : Object{public override string ToString(){return base.ToString();}}";
            cSharpSourceCode += "public class " + proxyClass.proxyClassName + "_Proxy : " + proxyClass.proxyClassName + "{\n";
            foreach(ProxyMethod pm in proxyClass.methodsList)
            {
                cSharpSourceCode += "\t" + "public " +
                                    ((pm.isOverride) ? "override " : "") +
                                    pm.methodReturnType + " " +
                                    pm.methodName + "(";
                foreach(ParameterInfo pi in pm.paramList)
                {
                    Console.WriteLine(pi.ToString());
                }
                cSharpSourceCode += "){" +
                    pm.body + "}\n";
                    
            }
            cSharpSourceCode += "}\n";
            return cSharpSourceCode;
        }
    }
}
